package com.duk.log;

import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
public class BizLogAspect
{

	Logger logger = Logger.getLogger(BizLogAspect.class);

	private static final ThreadLocal<String> params = new ThreadLocal<String>();

	public static void setLogParams(String value)
	{
		params.set(value);
	}

	public static String getLogParams()
	{
		return params.get();
	}

	private MongoLogger mongoLogger;

	// Controller层切点
	@Pointcut("@annotation(com.duk.log.BizLog)")
	public void controllerAspect()
	{
	}

	/**
	 * 前置通知 用于拦截Controller层记录用户的操作
	 * 
	 * @param joinPoint
	 *            切点
	 */
	@Before("controllerAspect()")
	public void before(JoinPoint joinPoint)
	{
		System.out.println("==========执行controller前置通知===============");
		params.remove();
		//
		// try {
		//
		// String targetName = joinPoint.getTarget().getClass().getName();
		// String methodName = joinPoint.getSignature().getName();
		// Object[] arguments = joinPoint.getArgs();
		// Class<?> targetClass = Class.forName(targetName);
		// Method[] methods = targetClass.getMethods();
		// String code = null;
		// String operation = null;
		// BizLogType type = null;
		// // 获得被拦截方法上的注解信息,待优化,应该缓存
		// for (Method method : methods) {
		// if (method.getName().equals(methodName)) {
		// Class<?>[] clazzs = method.getParameterTypes();
		// if (clazzs.length == arguments.length) {
		// code = method.getAnnotation(BizLog.class).code();
		// operation = method.getAnnotation(BizLog.class)
		// .operation();
		// type = method.getAnnotation(BizLog.class).type();
		// break;
		// }
		// }
		// }
		//
		// HttpServletRequest request = ((ServletRequestAttributes)
		// RequestContextHolder
		// .getRequestAttributes()).getRequest();
		// String requestIp = request.getRemoteAddr();
		// // 拿到后台管理登录的用户
		// // User user = request.getSession().getAttribute("USER");
		// // String username = user.getUsername();
		//
		// // 记录日志
		// BizLogData log = new BizLogData();
		// log.setCode(code);
		// log.setOperateTime(new Date());
		// log.setOperation(operation);
		// log.setSuccess(true);
		// if (type == null || type == BizLogType.CONSOLE) {
		// System.out.println(log);
		// } else if (type == BizLogType.MONGODB) {
		// mongoLogger.addLogger(log);
		// }
		//
		// System.out.println("=====controller后置通知结束=====");
		// } catch (Exception e) {
		// // 记录本地异常日志
		// }
	}

	// 配置controller环绕通知,使用在方法aspect()上注册的切入点
	// @Around("controllerAspect()")
	// public void around(JoinPoint joinPoint) {
	// System.out.println("==========开始执行controller环绕通知===============");
	// long start = System.currentTimeMillis();
	//
	// try {
	// ((ProceedingJoinPoint) joinPoint).proceed();
	// long end = System.currentTimeMillis();
	// if (logger.isInfoEnabled()) {
	// logger.info("around " + joinPoint + "\tUse time : "
	// + (end - start) + " ms!");
	// }
	// System.out.println("==========结束执行controller环绕通知===============");
	// } catch (Throwable e) {
	// long end = System.currentTimeMillis();
	// if (logger.isInfoEnabled()) {
	// logger.info("around " + joinPoint + "\tUse time : "
	// + (end - start) + " ms with exception : "
	// + e.getMessage());
	// }
	// }
	// }

	/**
	 * 后置通知 用于拦截Controller层记录用户的操作
	 * 
	 * @param joinPoint
	 *            切点
	 */
	@After("controllerAspect()")
	public void after(JoinPoint joinPoint)
	{
		try
		{
			String targetName = joinPoint.getTarget().getClass().getName();
			String methodName = joinPoint.getSignature().getName();
			Object[] arguments = joinPoint.getArgs();
			Class<?> targetClass = Class.forName(targetName);
			Method[] methods = targetClass.getMethods();
			String code = null;
			String operation = null;
			BizLogType type = null;
			// 获得被拦截方法上的注解信息,待优化,应该缓存
			for (Method method : methods)
			{
				if (method.getName().equals(methodName))
				{
					Class<?>[] clazzs = method.getParameterTypes();
					if (clazzs.length == arguments.length)
					{
						code = method.getAnnotation(BizLog.class).code();
						operation = method.getAnnotation(BizLog.class).operation();
						type = method.getAnnotation(BizLog.class).type();
						break;
					}
				}
			}

			// 记录日志
			BizLogData log = new BizLogData();
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
					.getRequest();
			String requestIp = request.getRemoteAddr();
			// // 拿到后台管理登录的用户
			// // User user = request.getSession().getAttribute("USER");
			// // String username = user.getUsername();
			log.setCode(code);
			log.setOperateTime(new Date());
			log.setOperation(operation);
			log.setSuccess(true);
			log.setIp(requestIp);
			String str = params.get();
			if (str != null)
			{
				log.setParams(str);
			}
			if (type == null || type == BizLogType.CONSOLE)
			{
				System.out.println(log);
			} else if (type == BizLogType.MONGODB)
			{
				mongoLogger.addLogger(log);
			}

			System.out.println("=====controller后置通知结束=====");
		} catch (Exception e)
		{
			// 记录本地异常日志
		}
	}

	// 配置后置返回通知,使用在方法aspect()上注册的切入点
	// @AfterReturning("controllerAspect()")
	// public void afterReturn(JoinPoint joinPoint) {
	// System.out.println("=====执行controller后置返回通知=====");
	// }

	/**
	 * 异常通知 用于拦截记录异常日志
	 * 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public void afterThrowing(JoinPoint joinPoint, Throwable e)
	{

		try
		{

			String targetName = joinPoint.getTarget().getClass().getName();
			String methodName = joinPoint.getSignature().getName();
			Object[] arguments = joinPoint.getArgs();
			Class<?> targetClass = Class.forName(targetName);
			Method[] methods = targetClass.getMethods();
			String code = null;
			String operation = null;
			BizLogType type = null;
			// 获得被拦截方法上的注解信息,待优化,应该缓存
			for (Method method : methods)
			{
				if (method.getName().equals(methodName))
				{
					Class<?>[] clazzs = method.getParameterTypes();
					if (clazzs.length == arguments.length)
					{
						code = method.getAnnotation(BizLog.class).code();
						operation = method.getAnnotation(BizLog.class).operation();
						type = method.getAnnotation(BizLog.class).type();
						break;
					}
				}
			}
			// 记录日志
			BizLogData log = new BizLogData();
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
					.getRequest();
			String requestIp = request.getRemoteAddr();
			// // 拿到后台管理登录的用户
			// // User user = request.getSession().getAttribute("USER");
			// // String username = user.getUsername();
			log.setCode(code);
			log.setOperateTime(new Date());
			log.setOperation(operation);
			log.setSuccess(true);
			log.setIp(requestIp);
			if (params.get() != null)
			{
				log.setParams(params.get());
			}
			if (type == null || type == BizLogType.CONSOLE)
			{
				System.out.println(log);
			} else if (type == BizLogType.MONGODB)
			{
				mongoLogger.addLogger(log);
			}
			/* ========控制台输出========= */
			System.out.println("=====异常通知开始=====");
			System.out.println("异常代码:" + e.getClass().getName());
			System.out.println("异常信息:" + e.getMessage());
			System.out.println("异常方法:"
					+ (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")
					+ "." + operation);
			/* ==========数据库日志========= */

			System.out.println("=====异常通知结束=====");
		} catch (Exception ex)
		{
			// 记录本地异常日志
			logger.error("==异常通知异常==");
		}

	}
}
